package top.lixunda.commerce.common.core.controller;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import top.lixunda.commerce.common.core.controller.wrapper.BaseDataQuerySqlWrapper;
import top.lixunda.commerce.common.core.controller.wrapper.BaseDataUpdateSqlWrapper;
import top.lixunda.commerce.common.core.controller.wrapper.EntityUpdateWrapper;
import top.lixunda.commerce.common.core.controller.wrapper.PageWrapper;
import top.lixunda.commerce.common.core.exception.InternalApiException;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

/**
 * @author LiXunda
 * @version time:2019/10/11 20:14
 * <p>
 * 不返回MessageObject，直接返回调用方需要的对象
 * @see IEntityController
 */
@SuppressWarnings({"WeakerAccess" , "unused"})
@Slf4j
public class BaseEntityController<M extends ServiceImpl<N, T>, N extends BaseMapper<T>, T> implements IEntityController<T> {

    @SuppressWarnings("SpringJavaAutowiredMembersInspection")
    @Autowired
    protected M m;

    public IService<T> getBaseService() {
        return m;
    }

    public BaseMapper<T> getBaseMapper() {
        return m.getBaseMapper();
    }

    @Override
    public T save(T entity) {
        log.debug("save {}", entity);
        boolean success = this.getBaseService().save(entity);
        log.debug("save {}", entity);
        if (success) {
            return entity;
        } else {
            throw new InternalApiException("插入数据失败");
        }
    }

    @Override
    public T saveOrUpdate(T entity) {
        getBaseService().saveOrUpdate(entity);
        return entity;
    }

    @Override
    public boolean saveOrUpdate(EntityUpdateWrapper<T> entityUpdateWrapper) {
        return this.getBaseService().saveOrUpdate(entityUpdateWrapper.getEntity(),
                entityUpdateWrapper.getWrapper().toUpdateWrapper());
    }

    @Override
    public List<T> saveBatch(List<T> entityList, int batchSize) {
        log.debug("saveBatch {}", entityList);
        getBaseService().saveBatch(entityList, batchSize);
        log.debug("saveBatch {}", entityList);
        return entityList;
    }

    @Override
    public List<T> saveBatch(List<T> entityList) {
        log.debug("saveBatch {}", entityList);
        this.getBaseService().saveBatch(entityList);
        log.debug("saveBatch {}", entityList);
        return entityList;
    }

    @Override
    public List<T> saveOrUpdateBatch(List<T> entityList, int batchSize) {
        log.debug("saveOrUpdateBatch {}", entityList);
        getBaseService().saveOrUpdateBatch(entityList, batchSize);
        log.debug("saveOrUpdateBatch {}", entityList);
        return entityList;
    }

    @Override
    public List<T> saveOrUpdateBatch(List<T> entityList) {
        log.debug("saveOrUpdateBatch {}", entityList);
        this.getBaseService().saveOrUpdateBatch(entityList);
        log.debug("saveOrUpdateBatch {}", entityList);
        return entityList;
    }

    @Override
    public boolean removeById(String id) {
        return getBaseService().removeById(id);
    }

    @Override
    public boolean removeByMap(Map<String, Object> columnMap) {
        return getBaseService().removeByMap(columnMap);
    }

    @Override
    public boolean remove(BaseDataUpdateSqlWrapper<T> queryWrapper) {
        return getBaseService().remove(queryWrapper.toUpdateWrapper());
    }

    @Override
    public boolean removeByIds(List<String> idList) {
        return getBaseService().removeByIds(idList);
    }

    @Override
    public boolean updateById(T entity) {
        return getBaseService().updateById(entity);
    }

    @Override
    public boolean update(EntityUpdateWrapper<T> entityUpdateWrapper) {
        return getBaseService().update(entityUpdateWrapper.getEntity(), entityUpdateWrapper.toUpdateWrapper());
    }

    @Override
    public boolean update(BaseDataUpdateSqlWrapper<T> updateWrapper) {
        return this.getBaseService().update(updateWrapper.toUpdateWrapper());
    }

    @Override
    public boolean updateBatchById(List<T> entityList, int batchSize) {
        return getBaseService().updateBatchById(entityList, batchSize);
    }

    @Override
    public boolean updateBatchById(List<T> entityList) {
        return this.getBaseService().updateBatchById(entityList);
    }

    @Override
    public T getById(String id) {
        return getBaseService().getById(id);
    }

    @Override
    public List<T> listByIds(List<String> idList) {
        return (List<T>) getBaseService().listByIds(idList);
    }

    @Override
    public List<T> listByMap(Map<String, Object> columnMap) {
        return (List<T>) getBaseService().listByMap(columnMap);
    }

    @Override
    public T getOne(BaseDataQuerySqlWrapper<T> queryWrapper) {
        log.debug("getOne {}", queryWrapper);
        return getBaseService().getOne(queryWrapper.toQueryWrapper(), false);
    }

    @Override
    public Map<String, Object> getMap(BaseDataQuerySqlWrapper<T> queryWrapper) {
        return getBaseService().getMap(queryWrapper.toQueryWrapper());
    }

    @Override
    public int count(BaseDataQuerySqlWrapper<T> queryWrapper) {
        return getBaseService().count(queryWrapper.toQueryWrapper());
    }

    @Override
    public int count() {
        return getBaseService().count();
    }

    @Override
    public List<T> list(BaseDataQuerySqlWrapper<T> queryWrapper) {
        return getBaseService().list(queryWrapper.toQueryWrapper());
    }

    @Override
    public List<T> list() {
        return this.getBaseService().list();
    }

    @Override
    public Page<T> page(PageWrapper<T> pageWrapper) {
        return (Page<T>) this.getBaseService().page(pageWrapper.getPage(),
                pageWrapper.getWrapper().toQueryWrapper());
    }

    @Override
    public Page<T> page(Page<T> page) {
        return (Page<T>) this.getBaseService().page(page);
    }

    @Override
    public Page<T> page(BaseDataQuerySqlWrapper<T> querySqlWrapper) {
        Long[] integers = querySqlWrapper.getOtherBlock().getPage();
        Page<T> page = new Page<>(integers[0], integers[1]);
        return (Page<T>) this.getBaseService().page(page, querySqlWrapper.toQueryWrapper());
    }

    @Override
    public Page<Map<String, Object>> pageMaps(Page<T> page) {
        return (Page<Map<String, Object>>) this.getBaseService().pageMaps(page);
    }

    @Override
    public Page<Map<String, Object>> pageMaps(PageWrapper<T> pageWrapper) {
        return (Page<Map<String, Object>>) this.getBaseService().pageMaps(pageWrapper.getPage(),
                pageWrapper.getWrapper().toQueryWrapper());
    }

    @Override
    public List<Map<String, Object>> listMaps(BaseDataQuerySqlWrapper<T> queryWrapper) {
        return getBaseService().listMaps(queryWrapper.toQueryWrapper());
    }

    @Override
    public List<Map<String, Object>> listMaps() {
        return this.getBaseService().listMaps();
    }

    /**
     * 级联分页
     *
     * @param page       分页数据，类型是自定义的级联后实体类DTO
     * @param wrapper    条件，基于基准表的条件构造器,可以在传入前使用select设置只查询id加快查询速度
     * @param service    基准表的service，用户获取分页id数据
     * @param idFunction 获取Id的Function, 用于获取基准表实体类的id
     * @param convertFun 转换Function，将连表数据转换为级联数据
     * @param <E>        基准表实体类
     * @param <D>        级联数据实体类
     * @return 级联数据列表
     */
    public <E, D> Page<D> convertPage(Page<D> page, Wrapper<E> wrapper, IService<E> service,
                                      Function<E, String> idFunction, Function<List<T>, List<D>> convertFun) {
        IPage<E> goodOrderPage;
        if (wrapper == null) {
            goodOrderPage = service.page(new Page<E>().setSize(page.getSize()).setCurrent(page.getCurrent()));
        } else {
            goodOrderPage = service.page(new Page<E>().setSize(page.getSize()).setCurrent(page.getCurrent()), wrapper);
        }
        page.setSize(goodOrderPage.getSize()).setTotal(goodOrderPage.getTotal()).setPages(goodOrderPage.getPages())
                .setCurrent(goodOrderPage.getCurrent());
        List<E> entityList = goodOrderPage.getRecords();
        if (entityList.size() == 0) {
            return page.setRecords(Collections.emptyList());
        }
        List<String> idList = new ArrayList<>(entityList.size());
        for (E e : entityList) {
            idList.add(idFunction.apply(e));
        }
        List<T> dtoList = getBaseMapper().selectBatchIds(idList);
        page.setRecords(convertFun.apply(dtoList));
        return page;
    }

}
